package de.koller.so.render.logo;

import de.koller.oceanFramework.math.Vec3;
import de.koller.oceanFramework.util.ColorIntUtil;
import de.koller.so.render.proto.Sphere2D;
import java.awt.image.BufferedImage;

public class LightMap {

	public final int[][] basicColor;
	private final int[][] lightColor;
	public final Vec3[][] normal;
	public final Vec3 lightN;
	private final HeightMap heightMap;

	public LightMap( Vec3 lN, HeightMap heightMap ) {
		int w = heightMap.map.length; int h = heightMap.map[0].length;
		this.basicColor = new int[ w ][ h ];
		this.lightColor = new int[ w ][ h ];
		this.normal = new Vec3[ w ][ h ];
		this.lightN = lN;
		this.heightMap = heightMap;
		
		calculateNormals();
	}
	
	public void basicColor() {
		for( int x = 0; x < lightColor.length; x++ )
			for( int y = 0;  y < lightColor[0].length; y++ ) 
				lightColor[x][y] = basicColor[x][y];
	}
	
	public void calcBasicLight() {
		for( int x = 0; x < lightColor.length; x++ )
			for( int y = 0;  y < lightColor[0].length; y++ ) 
				lightColor[x][y] = handleColor( x, y );
	}
	
	private int handleColor( int x, int y ) {
		Vec3 n = normal[x][y];
		n = n.newInstance().normalize();

		Vec3 ln = lightN.newInstance();
		ln = ln.normalize();

		float a = (float)ln.angleBetween( n );
		if( a > Math.PI / 2f )
			return 0xff000000;

		int c = 0xff - (int)(a / (float)(Math.PI / 2f) * 255f);
		int ambientC = ColorIntUtil.getIntColor( 0xff, c, c, c );

		//specular
		Vec3 h = new Vec3( ln.getX(), ln.getY(), ln.getZ() ).add( new Vec3( 0, 0, 1 ) ).normalize();
		double specular = Math.pow( Math.max( 0, n.dot( h ) ), 350 );

		int sr = ColorIntUtil.clampSegment( (int)(specular * 0xff) );
		int sg = ColorIntUtil.clampSegment( (int)(specular * 0xff) );
		int sb = ColorIntUtil.clampSegment( (int)(specular * 0xff) );

		return ColorIntUtil.add( ambientC, ColorIntUtil.getIntColor( 0xff, sr, sg, sb ) );
	}
	
	public BufferedImage getVisual() {
		BufferedImage i = new BufferedImage( lightColor.length, lightColor[0].length, BufferedImage.TYPE_INT_ARGB );
		for( int x = 0; x < lightColor.length; x++ )
			for( int y = 0;  y < lightColor[0].length; y++ ) {
				i.setRGB( x, y, lightColor[x][y] );
			}
		
		return i;
	}

	private void calculateNormals() {
		for( int x = 0; x < heightMap.map.length; x++ )
			for( int y = 0;  y < heightMap.map[0].length; y++ ) {
				double x0 = x >= heightMap.map.length-1 ? heightMap.map[x][y] : heightMap.map[x+1][y];
				double x1 = x <= 0 ? heightMap.map[x][y] : heightMap.map[x-1][y];
				double y0 = y >= heightMap.map[0].length-1 ? heightMap.map[x][y] : heightMap.map[x][y+1];
				double y1 = y <= 0 ? heightMap.map[x][y] : heightMap.map[x][y-1];
				
				Vec3 n = new Vec3( -(x1-x0), -(y1-y0), 4 ).normalize();
				normal[x][y] = n;
			}
	}
}
